package figure8.Network;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.PriorityBlockingQueue;

import figure8.Track;
import figure8.Network.Message.Type;
import figure8.events.NetworkDisconnectEvent;
import figure8.events.NetworkEventListener;
import figure8.events.NetworkEventSource;
import figure8.events.NetworkMessageEvent;
import figure8.events.NetworkNewClientEvent;
import figure8.events.TrackAddedEvent;
import figure8.events.TrackEventListener;
import figure8.events.TrackRemovedEvent;

public class Client extends NetworkEventSource implements Runnable, NetworkConnection {
	protected Socket socket;
	protected boolean host;
	protected int id;
	
	protected boolean disconnect = false;
	
	Reader input;
	PrintWriter output;

	protected Queue<Message> sending;
	protected Queue<Message> received;

	protected List<NetworkEventListener> listeners;

	public Client(Socket socket, boolean host, int id) {
		super();
		
		this.host = host;
		this.id = id;
		
		this.socket = socket;
		this.sending = new PriorityBlockingQueue<Message>();

		this.received = new LinkedList<Message>();

		try {
			this.input = new BufferedReader(new InputStreamReader(
					socket.getInputStream()));

			this.output = new PrintWriter(socket.getOutputStream(), true);
		} catch (IOException e) {
			System.err.println("Socket error.");
		}
	}

	@Override
	public void run() {
		System.out.println("Network: New Client running.");
		
		try {
			while (!disconnect) {
				Message message = receive();
				
				System.out.println("Network: received " + message);
				
				if (message.type == Type.SERVER_SHUTDOWN) {
					System.out.println("Disconnected (" + message.data + ").");
					disconnect = true;
				}
				
				if (message.type == Type.YOU_ARE) {
					this.id = Integer.parseInt(message.data);
					
					System.out.println("I am client " + this.id);
				} else if (message.type == Type.CLIENT_CHAT) {
					//new __HORRIBLE_CHAT_DEMO(null, message.data);
				} else {
					this.fireNetworkMessageEvent(message, this);
				}
				
				this.received.add(message);
			}

			this.input.close();
			this.output.close();
			socket.close();
		} catch (IOException e) {
			this.fireNetworkDisconnectEvent();
		}
	}
	
	public void disconnect() {
		this.disconnect = true;
	}
	
	private Message receive() throws IOException {
		int next;

		String message = "";

		// Read length
		while (true) {
			next = this.input.read();

			if (next == -1) {
				System.exit(1);
			}

			if ((char) next == ' ') {
				break;
			}

			message += (char) next;
		}

		int length = Integer.parseInt(message);

		message = "";

		for (int i = 0; i < length; ++i) {
			message += (char) this.input.read();
		}

		return new Message(message);
	}

	public void queue(Message message) {
		this.sending.add(message);
	}

	public void send(Message message) {
		String data = message.encode();
		
		System.out.println("Network: Sending " + message);
		
		this.output.print(data.length() + " " + data);
		this.output.flush();
	}
	
	@Override
	public void send(Message message, Client exclude) {
		if (exclude != this) {
			this.send(message);
		}
	}
	
	public String getName() {
		return "Undistinguished Client";
	}

	@Override
	public boolean isHost() {
		return false;
	}
}
